/**
 * 
 */
package services.communication.chat;

import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import org.example.www.communication.ChatService.ChatRoom;
import org.example.www.communication.ChatService.CommunicationChatService_PortType;

/**
 * La clase es un cliente de chat, que utiliza un
 * {@link CommunicationChatService_PortType} para acceder al web-sevice de chat.<BR/>
 * 
 * @author lito
 */
public class SimpleChatClient implements SimpleChatClientIF {
	
	/**
	 * El identificador del usuario de este cliente de chat.
	 */
	private String								clientID;
	
	/**
	 * Conjunto de salas de cha a las que este cliente esta suscripto.
	 */
	private Set<String>							registeredChatRooms;
	
	/**
	 * El proxy para acceder al web-service de chat.
	 */
	private CommunicationChatService_PortType	chatServiceProxy;
	
	/**
	 * Cinstrucotr por defecto, inicializa el ic del cliente y el proxy en nulo.
	 * El conjunto de salones de chat a los que se esta suscripto en vacio.
	 */
	public SimpleChatClient() {
		this.clientID = null;
		this.registeredChatRooms = new HashSet<String>();
		this.chatServiceProxy = null;
	}
	
	/**
	 * @return Un conjunto de salas de chat.
	 * @throws RuntimeException
	 *         Si ocurre una excepcion remota al usar el proxy.
	 */
	public synchronized Set<ChatRoom> getActiveChatRooms() {
		try {
			Set<ChatRoom> activeChatRoomsSet = new HashSet<ChatRoom>();
			ChatRoom[] activeChatRooms = this.chatServiceProxy
					.getActiveChatRooms();
			for (int i = 0; i < activeChatRooms.length; ++i) {
				activeChatRoomsSet.add(activeChatRooms[i]);
			}
			return activeChatRoomsSet;
		} catch (RemoteException e) {
			throw new RuntimeException(ERROR_MSG_GET_ACTIVE_CHAT_ROOMS, e);
		}
	}
	
	/**
	 * Entra a la sala de chat pasada como parametro, agregandola al conjunto
	 * inrno de salas de chat a las que se esta suscripto.
	 * 
	 * @param chatRoomID
	 *        El identificador de la sala a la cual se quiere entrar.
	 * @throws RuntimeException
	 *         Si ocurre una excepcion remota.<BR/>
	 *         Si se intenta entrar a una sala de chat a la que ya se esta
	 *         suscripto.
	 */
	public synchronized void enterChatRoom(String chatRoomID) {
		try {
			boolean could = this.chatServiceProxy.enterChatRoom(chatRoomID,
					this.clientID);
			if (could) {
				this.registeredChatRooms.add(chatRoomID);
				return;
			} else {
				throw new RuntimeException(ERROR_MSG_ALREADY_IN_CHAT_ROOMS);
			}
		} catch (RemoteException e) {
			throw new RuntimeException(ERROR_MSG_ENTER_CHAT_ROOMS, e);
		}
	}
	
	/**
	 * Retira este cliente de la sala de chat pasada como parametro del servidor
	 * mediante el proxy. y quita la sala del conjunto de salas a las que este
	 * cliente esta suscripto.
	 * 
	 * @param chatRoomID
	 *        El identificador de la sala de la cual se quiere salir.
	 */
	public synchronized void quitChatRoom(String chatRoomID) {
		try {
			this.chatServiceProxy.quitChatRoom(chatRoomID, this.clientID);
			this.registeredChatRooms.remove(chatRoomID);
		} catch (RemoteException e) {
			throw new RuntimeException(ERROR_MSG_QUIT_CHAT_ROOMS, e);
		}
	}
	
	/**
	 * Envia el mensaje al salon de chat especificado utilizando el proxy.
	 * 
	 * @param chatRoomID
	 *        El identificador del salon del chat al que se enviara el mensaje.
	 * @param msg
	 *        El mensaje a enviar.
	 * @return El mensaje que se veran los otros usuarios.
	 * @throws RuntimeException
	 *         Si ocurre una excepcion remota.
	 */
	public synchronized String sendMsg(String chatRoomID, String msg) {
		try {
			return this.chatServiceProxy.sendMsg(chatRoomID, clientID, msg);
		} catch (RemoteException e) {
			throw new RuntimeException(ERROR_MSG_QUIT_CHAT_ROOMS, e);
		}
	}
	
	/**
	 * Solicita a cada uno de los salones de chat a los cuales esta suscripto
	 * este cliente que le envien los mensajes pendientes. Con lo cual conforma
	 * una tabla de hash y la retorna.
	 * 
	 * @return Una tabla de hash con los mensajes pendientes para cada salon de
	 *         chat al que esta suscripto este cliente.
	 * @throws RuntimeException
	 *         Si ocurre un excepcion remota.
	 */
	public synchronized Map<String, List<String>> recivePendingMsgsPerChatRoom() {
		try {
			Map<String, List<String>> pendinMsgsPerChatRoom = new Hashtable<String, List<String>>();
			for (String chatRoomID : this.registeredChatRooms) {
				String[] msgsArray = this.chatServiceProxy.reciveMsgs(
						chatRoomID, clientID);
				List<String> msgsList = new Vector<String>();
				if (msgsArray != null) {
					msgsList = Arrays.asList(msgsArray);
				}
				pendinMsgsPerChatRoom.put(chatRoomID, msgsList);
			}
			return pendinMsgsPerChatRoom;
		} catch (RemoteException e) {
			throw new RuntimeException(ERROR_MSG_RECIVE_PENDING_MSGS, e);
		}
	}
	
	/**
	 * @return El proxy para acceder al web-service de chat.
	 */
	public synchronized final CommunicationChatService_PortType getChatServiceProxy() {
		return chatServiceProxy;
	}
	
	/**
	 * @param chatServiceProxy
	 *        El proxy para acceder al web-service de chat.
	 */
	public synchronized final void setChatServiceProxy(
			CommunicationChatService_PortType chatServiceProxy) {
		this.chatServiceProxy = chatServiceProxy;
	}
	
	/**
	 * @return El identificador del usuario de este cliente de chat.
	 */
	public synchronized final String getClientID() {
		return clientID;
	}
	
	/**
	 * Si el parametro es distinto del id de cliente actual, se quita el cliente
	 * de las salas de chat a laas que este suscripto y se cambia el id; si no,
	 * no hace nada.
	 * 
	 * @param clientID
	 *        El identificador del usuario de este cliente de chat.
	 */
	public synchronized final void setClientID(String clientID) {
		if (this.clientID != null && !this.clientID.equals(clientID)) {
			Set<String> aux = new HashSet<String>(this.registeredChatRooms);
			for (String chatRoomID : aux) {
				this.quitChatRoom(chatRoomID);
			}
		}
		this.clientID = clientID;
	}
	
	/**
	 * @return Conjunto de salas de cha a las que este cliente esta suscripto.
	 */
	public synchronized final Set<String> getRegisteredChatRooms() {
		return registeredChatRooms;
	}
	
}
